﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using sAstar;

namespace DemoAstarAlgorithm
{
    class cEnemies : cSprite
    {
        public List<Rectangle> m_rListFrame { get; set; }
        public int m_iDirection { get; set; }
        public int m_iIDFrame { get; set; }
        public int m_iIDlife;
        public int m_iTimeSinceLastFrame;
        public int m_iCount;
        private int m_ix;
        private int m_iy;
        public Point m_pGoal;
        private int m_iDeltaPosition = 0;
        public bool m_bAlive = false;
        private Random m_rCWay = new Random();
        private int m_iNewDirection;
        private Vector2 m_v2New;
        private Vector2 m_v2Current;
        private AStarAlgorithm m_Astar;

        public cEnemies(Texture2D newTexture, Vector2 newPosition)
            : base(newTexture, newPosition)
        {
            m_rListFrame = new List<Rectangle>();
            m_iDirection = 0;
            m_iIDFrame = 0;
            m_iIDlife = 2;
            m_iTimeSinceLastFrame = 0;
            m_bAlive = true;
            CatHinhBug();
            m_iCount = 0;
            m_pGoal = new Point(12, 14);
            m_iNewDirection = 0;
            m_Astar = new AStarAlgorithm(null, 0);
            m_ix = m_iy = 0;
            m_v2New = new Vector2(0, 0);
            m_v2Current = new Vector2(0, 0);
        }

        public void CatHinhBug()
        {
            m_rListFrame.Add(new Rectangle(0, 40, 40, 40));//Frame[0]
            m_rListFrame.Add(new Rectangle(40, 40, 40, 40));//Frame[1]
            m_rListFrame.Add(new Rectangle(80, 40, 40, 40));//Frame[2]           
            m_rListFrame.Add(new Rectangle(120, 40, 40, 40));//Frame[3]
            m_rListFrame.Add(new Rectangle(0, 0, 40, 40)); //Frame[4]
            m_rListFrame.Add(new Rectangle(40, 0, 40, 40)); //Frame[5]
            m_rListFrame.Add(new Rectangle(80, 0, 40, 40));//Frame[6]           
            m_rListFrame.Add(new Rectangle(120, 0, 40, 40));//Frame[7]
            m_rListFrame.Add(new Rectangle(0, 80, 40, 40));//Frame[8]
            m_rListFrame.Add(new Rectangle(40, 80, 40, 40));//Frame[9]
            m_rListFrame.Add(new Rectangle(80, 80, 40, 40)); //Frame[10]            
            m_rListFrame.Add(new Rectangle(120, 80, 40, 40));//Frame[11]
            m_rListFrame.Add(new Rectangle(0, 120, 40, 40));//Frame[12]
            m_rListFrame.Add(new Rectangle(40, 120, 40, 40));//Frame[13]
            m_rListFrame.Add(new Rectangle(80, 120, 40, 40));//Frame[14]
            m_rListFrame.Add(new Rectangle(120, 120, 40, 40));//Frame[15]

            m_rListFrame.Add(new Rectangle(0, 240, 40, 40));    //Frame[16]
            m_rListFrame.Add(new Rectangle(40, 240, 40, 40));   //Frame[17]
            m_rListFrame.Add(new Rectangle(80, 240, 40, 40));   //Frame[18]
            m_rListFrame.Add(new Rectangle(120, 240, 40, 40));  //Frame[19]
            m_rListFrame.Add(new Rectangle(0, 200, 40, 40));    //Frame[20]
            m_rListFrame.Add(new Rectangle(40, 200, 40, 40));   //Frame[21]
            m_rListFrame.Add(new Rectangle(80, 200, 40, 40));   //Frame[22]           
            m_rListFrame.Add(new Rectangle(120, 200, 40, 40));  //Frame[23]
            m_rListFrame.Add(new Rectangle(0, 280, 40, 40));    //Frame[24]
            m_rListFrame.Add(new Rectangle(40, 280, 40, 40));   //Frame[25]
            m_rListFrame.Add(new Rectangle(80, 280, 40, 40));   //Frame[26]           
            m_rListFrame.Add(new Rectangle(120, 280, 40, 40));  //Frame[27]
            m_rListFrame.Add(new Rectangle(0, 320, 40, 40)); //Frame[28]
            m_rListFrame.Add(new Rectangle(40, 320, 40, 40)); //Frame[29]
            m_rListFrame.Add(new Rectangle(80, 320, 40, 40));//Frame[30]           
            m_rListFrame.Add(new Rectangle(120, 320, 40, 40));//Frame[31]
        }

        public void UpdateFrame(GameTime gameTime)
        {
            if (m_iNewDirection != m_iDirection) //Đổi hướng
            {
                m_iDirection = m_iNewDirection;
                m_iIDFrame = m_iNewDirection;
            }
            else
            {
                m_iCount += gameTime.ElapsedGameTime.Milliseconds;
                if (m_iCount > 100)
                {
                    m_iIDFrame++;
                    if (m_iIDFrame == m_iDirection + 4) //Nếu vựt qua khung hình di chuyển quay về hình đầu
                        m_iIDFrame = m_iDirection;
                    m_iCount = 0;
                }
            }
            NotOutSideScreenBug();
        }

        private void NotOutSideScreenBug()
        {
            if (m_v2Position.X < 20)
                m_v2Position = new Vector2(20, m_v2Position.Y);
            if (m_v2Position.Y < 40)
                m_v2Position = new Vector2(m_v2Position.X, 40);
            if (m_v2Position.X > (800 - 40 - 180))
                m_v2Position = new Vector2((800 - 40 - 180), m_v2Position.Y);
            if (m_v2Position.Y > (600 - 40 - 40))
                m_v2Position = new Vector2(m_v2Position.X, (600 - 40 - 40));
        }

        private int ChooseWay(int Way1, int Way2)
        {
            int Way = 0;
            do
            {
                Way = m_rCWay.Next(0, 4);
            }
            while (Way == Way1 || Way == Way2);
            return Way * 4;
        }

        private void WhatWay(int[, ,] map, int ID, int NowDirection, GameTime gameTime, int[] RNext)
        {
            if (m_iDeltaPosition >= 40 || m_iDeltaPosition == 0)
            {
                switch (NowDirection)
                {
                    case 0:
                        if (RNext[0] == 0)
                        {
                            if (RNext[2] == 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(1, 1);
                            if (RNext[2] == 0 && RNext[3] != 0)
                                m_iNewDirection = ChooseWay(1, 3);
                            if (RNext[2] != 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(1, 2);
                            if (RNext[2] != 0 && RNext[3] != 0)
                                m_iNewDirection = NowDirection;
                        }
                        else
                        {
                            if (RNext[2] == 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(0, 0);
                            if (RNext[2] == 0 && RNext[3] != 0)
                                m_iNewDirection = ChooseWay(0, 3);
                            if (RNext[2] != 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(0, 2);
                            if (RNext[2] != 0 && RNext[3] != 0)
                                m_iNewDirection = 4;
                        }
                        break;
                    case 4:
                        if (RNext[1] == 0)
                        {
                            if (RNext[2] == 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(0, 0);
                            if (RNext[2] == 0 && RNext[3] != 0)
                                m_iNewDirection = ChooseWay(0, 3);
                            if (RNext[2] != 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(0, 2);
                            if (RNext[2] != 0 && RNext[3] != 0)
                                m_iNewDirection = NowDirection;
                        }
                        else
                        {
                            if (RNext[2] == 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(1, 1);
                            if (RNext[2] == 0 && RNext[3] != 0)
                                m_iNewDirection = ChooseWay(1, 3);
                            if (RNext[2] != 0 && RNext[3] == 0)
                                m_iNewDirection = ChooseWay(1, 2);
                            if (RNext[2] != 0 && RNext[3] != 0)
                                m_iNewDirection = 0;
                        }
                        break;
                    case 8:
                        if (RNext[2] == 0)
                        {
                            if (RNext[0] == 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(3, 3);
                            if (RNext[0] == 0 && RNext[1] != 0)
                                m_iNewDirection = ChooseWay(1, 3);
                            if (RNext[0] != 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(0, 3);
                            if (RNext[0] != 0 && RNext[1] != 0)
                                m_iNewDirection = NowDirection;
                        }
                        else
                        {
                            if (RNext[0] == 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(2, 2);
                            if (RNext[0] == 0 && RNext[1] != 0)
                                m_iNewDirection = ChooseWay(1, 2);
                            if (RNext[0] != 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(0, 2);
                            if (RNext[0] != 0 && RNext[1] != 0)
                                m_iNewDirection = 12;
                        }
                        break;
                    case 12:
                        if (RNext[3] == 0)
                        {
                            if (RNext[0] == 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(2, 2);
                            if (RNext[0] == 0 && RNext[1] != 0)
                                m_iNewDirection = ChooseWay(1, 2);
                            if (RNext[0] != 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(0, 2);
                            if (RNext[0] != 0 && RNext[1] != 0)
                                m_iNewDirection = NowDirection;
                        }
                        else
                        {
                            if (RNext[0] == 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(3, 3);
                            if (RNext[0] == 0 && RNext[1] != 0)
                                m_iNewDirection = ChooseWay(1, 3);
                            if (RNext[0] != 0 && RNext[1] == 0)
                                m_iNewDirection = ChooseWay(0, 3);
                            if (RNext[0] != 0 && RNext[1] != 0)
                                m_iNewDirection = 8;
                        }
                        break;
                }
            }
            if (m_iNewDirection != m_iDirection) //Đổi hướng
            {
                m_iDirection = m_iNewDirection;
                m_iIDFrame = m_iNewDirection;
            }
            else
            {
                m_iCount += gameTime.ElapsedGameTime.Milliseconds;
                if (m_iCount > 100)
                {
                    m_iIDFrame++;
                    if (m_iIDFrame == m_iDirection + 4) //Nếu vựt qua khung hình di chuyển quay về hình đầu
                        m_iIDFrame = m_iDirection;
                    m_iCount = 0;
                }
            }
            switch (m_iNewDirection)
            {
                case 0:
                    m_v2Position += new Vector2(0, 1);
                    break;
                case 4:
                    m_v2Position += new Vector2(0, -1);
                    break;
                case 8:
                    m_v2Position += new Vector2(1, 0);
                    break;
                case 12:
                    m_v2Position += new Vector2(-1, 0);
                    break;
            }
            NotOutSideScreenBug();
        }

        public void MoveFree(GameTime gameTime, int[, ,] map, int IDmap) //Di chuyen
        {
            #region RNext
            int[] RNext = new int[4];
            if (m_ix == 12)
                RNext[0] = 1;
            else
                RNext[0] = map[IDmap, m_ix + 1, m_iy]; // 0 tren

            if (m_ix == 0)
                RNext[1] = 1;
            else
                RNext[1] = map[IDmap, m_ix - 1, m_iy]; // 4 duoi

            if (m_iy == 14)
                RNext[2] = 1;
            else
                RNext[2] = map[IDmap, m_ix, m_iy + 1]; // 8 phai

            if (m_iy == 0)
                RNext[3] = 1;
            else
                RNext[3] = map[IDmap, m_ix, m_iy - 1]; // 12 trai
            #endregion
            WhatWay(map, IDmap, m_iNewDirection, gameTime, RNext);
            NotOutSideScreenBug();
        }

        public void MoveAStar(GameTime gameTime)
        {
            m_v2Position += new Vector2(m_v2Current.Y, m_v2Current.X);
            if (m_v2Current == new Vector2(1, 0))
            {
                m_iNewDirection = 0;
                UpdateFrame(gameTime);
            }
            else
                if (m_v2Current == new Vector2(-1, 0))
                {
                    m_iNewDirection = 4;
                    UpdateFrame(gameTime);
                }
                else
                    if (m_v2Current == new Vector2(0, 1))
                    {
                        m_iNewDirection = 8;
                        UpdateFrame(gameTime);
                    }
                    else
                        if (m_v2Current == new Vector2(0, -1))
                        {
                            m_iNewDirection = 12;
                            UpdateFrame(gameTime);
                        }
            NotOutSideScreenBug();
        }

        public void Update(GameTime gameTime, int[, ,] map, int IDmap, Vector2 posWitch) //Di chuyen
        {
            m_Astar.Map = map;
            m_Astar.ID = IDmap;

            if (m_iIDlife == 1 || m_iIDlife == 4)
                return;
            else
            {
                if (m_iDeltaPosition >= 40)
                {
                    m_iDeltaPosition = 0;
                    m_iy = (int)((m_v2Position.X - 20) / 40);
                    m_ix = (int)((m_v2Position.Y - 40) / 40);
                    if (m_ix == 12 && m_iy == 14)
                    {
                        m_iIDlife = 3;
                    }
                    if (m_iIDlife == 3)
                        m_pGoal = new Point((int)(posWitch.Y - 40) / 40, (int)(posWitch.X - 20) / 40);
                    Vector2 next = m_Astar.GetNext(m_pGoal.X, m_pGoal.Y, m_ix, m_iy);
                    m_v2New = next;
                }
                if (m_v2New == new Vector2(0, 0))
                {
                    MoveFree(gameTime, map, IDmap);
                }
                else
                {
                    if (m_v2New != m_v2Current)
                    {
                        m_v2Current = m_v2New;
                    }
                    MoveAStar(gameTime);
                }
                m_iDeltaPosition += 1;
            }
        }

        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            float bgLayerDepth = m_v2Position.Y / 600.0f;
            switch (m_iIDlife)
            {
                case 1:
                    m_iTimeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                    Rectangle Frame11 = new Rectangle(0, 160, 40, 40);
                    Rectangle Frame12 = new Rectangle(40, 160, 40, 40);
                    Rectangle Frame13 = new Rectangle(80, 160, 40, 40);
                    Rectangle Frame14 = new Rectangle(120, 160, 40, 40);
                    if (m_iTimeSinceLastFrame < 300)
                        spriteBatch.Draw(m_tTexture, m_v2Position, Frame11, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                    else
                        if (m_iTimeSinceLastFrame < 600)
                            spriteBatch.Draw(m_tTexture, m_v2Position, Frame12, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                        else
                            if (m_iTimeSinceLastFrame < 900)
                                spriteBatch.Draw(m_tTexture, m_v2Position, Frame13, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                            else
                                if (m_iTimeSinceLastFrame < 1200)
                                {
                                    spriteBatch.Draw(m_tTexture, m_v2Position, Frame14, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                                }
                                else
                                {
                                    Game1.g_iCountEnemies--;
                                    if (Game1.g_iCountEnemies < 0)
                                        Game1.g_iCountEnemies = 0;
                                    m_bAlive = false;
                                }
                    break;
                case 2:
                    spriteBatch.Draw(m_tTexture, m_v2Position, m_rListFrame[m_iIDFrame], Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                    break;
                case 3:
                    spriteBatch.Draw(m_tTexture, m_v2Position, m_rListFrame[m_iIDFrame + 16], Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                    break;
                case 4:
                    m_iTimeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                    Rectangle Frame41 = new Rectangle(0, 360, 40, 40);
                    Rectangle Frame42 = new Rectangle(40, 360, 40, 40);
                    Rectangle Frame43 = new Rectangle(80, 360, 40, 40);
                    Rectangle Frame44 = new Rectangle(120, 360, 40, 40);
                    if (m_iTimeSinceLastFrame < 300)
                        spriteBatch.Draw(m_tTexture, m_v2Position, Frame41, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                    else
                        if (m_iTimeSinceLastFrame < 600)
                            spriteBatch.Draw(m_tTexture, m_v2Position, Frame42, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                        else
                            if (m_iTimeSinceLastFrame < 900)
                                spriteBatch.Draw(m_tTexture, m_v2Position, Frame43, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                            else
                                if (m_iTimeSinceLastFrame < 1200)
                                {
                                    spriteBatch.Draw(m_tTexture, m_v2Position, Frame44, Color.White, 0, Vector2.Zero, 1, SpriteEffects.None, bgLayerDepth);
                                }
                                else
                                {
                                    Game1.g_iCountEnemies--;
                                    if (Game1.g_iCountEnemies < 0)
                                        Game1.g_iCountEnemies = 0;
                                    m_bAlive = false;
                                }
                    break;
                default:
                    break;
            }
        }
    }
}

namespace DemoAstarAlgorithm
{
    class ManagerEnemies
    {
        public List<cEnemies> l_Enemies;
        public int m_iNumEnemies;
        public const int c_iMaxEnemies = 30;
        public TimeSpan m_tsTimeBornEnemies;

        public ManagerEnemies()
        {
            l_Enemies = new List<cEnemies>();
            m_iNumEnemies = 0;
            m_tsTimeBornEnemies = TimeSpan.Zero;
        }

        public void Update(GameTime gameTime, ContentManager content, String nameEnemis, int[, ,] matrix, int mapID, Vector2 posWitch)
        {
            m_tsTimeBornEnemies += gameTime.ElapsedGameTime;
            if (m_tsTimeBornEnemies > TimeSpan.FromSeconds(5))
            {
                m_tsTimeBornEnemies -= TimeSpan.FromSeconds(5);
                if (m_iNumEnemies < c_iMaxEnemies)
                {
                    l_Enemies.Add(new cEnemies(content.Load<Texture2D>(@"images/" + nameEnemis), new Vector2(20, 40)));
                    m_iNumEnemies++;
                }
            }
            for (int i = 0; i < m_iNumEnemies; i++)
            {
                if (l_Enemies[i].m_bAlive == false)
                {
                    l_Enemies.Remove(l_Enemies[i]);
                    i--;
                    m_iNumEnemies--;
                }
            }
            foreach (cEnemies enemie in l_Enemies)
            {
                enemie.Update(gameTime, matrix, mapID, posWitch);
            }
        }

        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            foreach (cEnemies enemie in l_Enemies)
            {
                enemie.Draw(spriteBatch, gameTime);
            }
        }
    }
}